//
//  testc.c
//  myapp
//
//  Created by mac on 2025/6/23.
//

#include "testc.h"

static int record_status = 0;

char *getSandboxHomeFromEnv(void)
{
    return getenv("HOME");
}

int open_file_to_save(FILE **out_file_ref)
{
    char *home = getSandboxHomeFromEnv();
    printf("sandbox home: %s\n", home);

    char *file_name = "/audio.aac";
    char sound_output_path[1024] = "";
    strcat(sound_output_path, home);
    strcat(sound_output_path, file_name);

    *out_file_ref = fopen(sound_output_path, "wb+");
    if (!*out_file_ref)
    {
        perror("Failed to open output file\n");
        return -1;
    }

    return 0;
}

AVCodecContext* open_coder(void)
{
    const AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");
    if (!codec) {
        fprintf(stderr, "libfdk_aac encoder not found\n");
        return NULL;
    }

    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
    if (!codec_ctx) {
        fprintf(stderr, "Failed to allocate codec context\n");
        return NULL;
    }

    codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;
    av_channel_layout_copy(&codec_ctx->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
    codec_ctx->sample_rate = 44100;
    codec_ctx->bit_rate = 0;
    codec_ctx->profile = FF_PROFILE_AAC_HE_V2;

    if (avcodec_open2(codec_ctx, codec, NULL) < 0)
    {
        avcodec_free_context(&codec_ctx);
        return NULL;
    }

    return codec_ctx;
}

void encode(AVCodecContext *av_c_ctx,
            AVFrame *frame,
            AVPacket *pkt,
            FILE *output_file)
{
    int ret = avcodec_send_frame(av_c_ctx, frame);
    if (ret < 0)
    {
        fprintf(stderr, "Error sending frame: %s\n", av_err2str(ret));
        return;
    }

    while (ret >= 0)
    {
        ret = avcodec_receive_packet(av_c_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        {
            return;
        }
        else if (ret < 0)
        {
            fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret));
            return;
        }

        fwrite(pkt->data, 1, pkt->size, output_file);
        fflush(output_file);
        av_packet_unref(pkt);
    }
}

void set_record_status(int status) { record_status = status; }

void free_mem(
    AVCodecContext *codec_ctx,
    uint8_t **src_data,
    uint8_t **dst_data,
    SwrContext *swr_ctx,
    AVPacket *pkt,
    AVFormatContext *fmt_ctx,
    AVFrame *av_frame,
    AVPacket *new_av_pkt,
    FILE *out_file,
    int16_t *sample_buffer)
{
    if (codec_ctx)
    {
        avcodec_free_context(&codec_ctx);
    }

    if (src_data)
    {
        if (src_data[0])
            av_freep(&src_data[0]);
        av_freep(&src_data);
    }

    if (dst_data)
    {
        if (dst_data[0])
            av_freep(&dst_data[0]);
        av_freep(&dst_data);
    }

    if (swr_ctx)
        swr_free(&swr_ctx);
    if (pkt)
        av_packet_free(&pkt);
    if (fmt_ctx)
        avformat_close_input(&fmt_ctx);
    if (av_frame)
        av_frame_free(&av_frame);
    if (new_av_pkt)
        av_packet_free(&new_av_pkt);
    if (out_file)
        fclose(out_file);
    if (sample_buffer)
    {
        av_free(sample_buffer);
    }
}

void record_audio(void)
{
    int ret = 0;
    char errors[1024] = {0};

    AVFormatContext *fmt_ctx = NULL;
    FILE *out_file = NULL;
    int count = 0;

    char *devicename = ":1"; // 使用第二个音频设备

    av_log_set_level(AV_LOG_DEBUG);
    record_status = 1;

    if (open_file_to_save(&out_file) != 0)
    {
        return;
    }

    avdevice_register_all();
    const AVInputFormat *input_format = av_find_input_format("avfoundation");

    AVDictionary *options = NULL;
    av_dict_set(&options, "sample_rate", "44100", 0);
    av_dict_set(&options, "channels", "2", 0);
    av_dict_set(&options, "format", "fltp", 0); // 明确请求平面浮点格式

    ret = avformat_open_input(&fmt_ctx, devicename, input_format, &options);
    av_dict_free(&options);

    if (ret < 0)
    {
        av_strerror(ret, errors, 1024);
        fprintf(stderr, "Failed to open audio device [%d] %s\n", ret, errors);
        fclose(out_file);
        return;
    }

    AVCodecContext *codec_ctx = open_coder();
    if (!codec_ctx)
    {
        fprintf(stderr, "Failed to open encoder\n");
        avformat_close_input(&fmt_ctx);
        fclose(out_file);
        return;
    }

    // 获取编码器要求的帧大小
    const int frame_size = codec_ctx->frame_size;
    printf("Encoder requires frame size: %d samples\n", frame_size);
    
    AVFrame *av_frame = av_frame_alloc();
    if (!av_frame)
    {
        fprintf(stderr, "Failed to allocate frame\n");
        free_mem(codec_ctx, NULL, NULL, NULL, NULL, fmt_ctx, NULL, NULL, out_file, NULL);
        return;
    }

    // 设置帧大小匹配编码器要求
    av_frame->nb_samples = frame_size;
    av_frame->format = AV_SAMPLE_FMT_S16;
    av_channel_layout_copy(&av_frame->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
    ret = av_frame_get_buffer(av_frame, 0);
    if (ret < 0) {
        fprintf(stderr, "Failed to allocate frame buffers\n");
        free_mem(codec_ctx, NULL, NULL, NULL, NULL, fmt_ctx, av_frame, NULL, out_file, NULL);
        return;
    }

    AVPacket *new_av_pkt = av_packet_alloc();
    if (!new_av_pkt)
    {
        fprintf(stderr, "Failed to allocate packet\n");
        free_mem(codec_ctx, NULL, NULL, NULL, NULL, fmt_ctx, av_frame, NULL, out_file, NULL);
        return;
    }

    SwrContext *swr_ctx = NULL;
    AVChannelLayout out_ch_layout, in_ch_layout;
    av_channel_layout_copy(&out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
    av_channel_layout_copy(&in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);

    // 关键修复1：匹配重采样器内部格式
    ret = swr_alloc_set_opts2(&swr_ctx,
                              &out_ch_layout,
                              AV_SAMPLE_FMT_S16,   // 输出格式：16位有符号整数
                              44100,
                              &in_ch_layout,
                              AV_SAMPLE_FMT_FLTP,  // 输入格式：平面浮点
                              44100,
                              0,
                              NULL);
    if (ret != 0) {
        fprintf(stderr, "Failed to allocate resampler\n");
        free_mem(codec_ctx, NULL, NULL, swr_ctx, NULL, fmt_ctx, av_frame, new_av_pkt, out_file, NULL);
        return;
    }
    
    if (swr_init(swr_ctx) < 0)
    {
        fprintf(stderr, "Failed to initialize resampler\n");
        free_mem(codec_ctx, NULL, NULL, swr_ctx, NULL, fmt_ctx, av_frame, new_av_pkt, out_file, NULL);
        return;
    }

    AVPacket *pkt = av_packet_alloc();
    if (!pkt)
    {
        fprintf(stderr, "Failed to allocate packet\n");
        free_mem(codec_ctx, NULL, NULL, swr_ctx, pkt, fmt_ctx, av_frame, new_av_pkt, out_file, NULL);
        return;
    }

    uint8_t **src_data = NULL, **dst_data = NULL;
    int src_linesize = 0, dst_linesize = 0;

    // 分配重采样缓冲区
    ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, 2, 
                                            frame_size * 4,  
                                            AV_SAMPLE_FMT_FLTP, 0); // 平面浮点格式
    if (ret < 0) { 
        fprintf(stderr, "Failed to allocate source sample buffers\n");
        free_mem(codec_ctx, src_data, dst_data, swr_ctx, pkt, 
                 fmt_ctx, av_frame, new_av_pkt, out_file, NULL);
        return;
     }
    
    ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, 2, 
                                            frame_size * 4,  
                                            AV_SAMPLE_FMT_S16, 0); // 输出格式
    if (ret < 0) { 
        fprintf(stderr, "Failed to allocate destination sample buffers\n");
        free_mem(codec_ctx, src_data, dst_data, swr_ctx, pkt, 
                 fmt_ctx, av_frame, new_av_pkt, out_file, NULL);
        return;
     }
    
    // 样本累积缓冲区
    int16_t *sample_buffer = NULL;
    int buffer_size = 0;
    int buffer_count = 0;
    const int samples_per_frame = frame_size * 2; // 立体声样本数 (2通道)

    // 关键修复2：计算输入格式的样本大小
    const int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLTP);
    const int in_sample_size = bytes_per_sample * 2; // 立体声

    // 主循环处理
    while (record_status)
    {
        ret = av_read_frame(fmt_ctx, pkt);
        if (ret == AVERROR(EAGAIN)) {
            usleep(5000);
            continue;
        }
        
        if (ret < 0) {
            if (ret != AVERROR_EOF) {
                av_strerror(ret, errors, 1024);
                fprintf(stderr, "Error reading packet: %s\n", errors);
            }
            break;
        }

        // 计算输入样本数
        int in_samples = pkt->size / in_sample_size;
        const uint8_t *cur_src = pkt->data;
        int samples_left = in_samples;
        
        // 关键修复3：处理平面格式数据
        while (samples_left > 0) {
            int chunk_samples = (samples_left > frame_size) ? frame_size : samples_left;
            int chunk_bytes = chunk_samples * in_sample_size;
            
            // 复制数据到重采样输入缓冲区
            // 对于平面格式，数据需要复制到正确的平面
            const uint8_t *chunk_data[2] = {
                cur_src, 
                cur_src + (chunk_samples * bytes_per_sample)
            };
            
            // 执行重采样
            int out_samples = swr_convert(swr_ctx, 
                                         dst_data, 
                                         frame_size * 4,
                                         chunk_data, 
                                         chunk_samples);
            
            if (out_samples < 0) {
                av_strerror(out_samples, errors, 1024);
                fprintf(stderr, "Resampling failed: %s\n", errors);
                break;
            }
            
            // 处理重采样后的数据
            int16_t *dst_samples = (int16_t *)dst_data[0];
            int samples_to_copy = out_samples * 2; // 立体声样本数
            
            // 扩展缓冲区
            if (buffer_count + samples_to_copy > buffer_size) {
                buffer_size = (buffer_count + samples_to_copy + samples_per_frame) * 2;
                int16_t *new_buf = av_realloc(sample_buffer, buffer_size * sizeof(int16_t));
                if (!new_buf) {
                    fprintf(stderr, "Failed to reallocate sample buffer\n");
                    break;
                }
                sample_buffer = new_buf;
            }
            
            // 复制到样本缓冲区
            memcpy(sample_buffer + buffer_count, dst_samples, samples_to_copy * sizeof(int16_t));
            buffer_count += samples_to_copy;
            
            // 移动指针
            cur_src += chunk_bytes;
            samples_left -= chunk_samples;
        }
        
        av_packet_unref(pkt);

        // 编码完整帧
        while (buffer_count >= samples_per_frame) {
            // 复制一帧数据到AVFrame
            memcpy(av_frame->data[0], sample_buffer, samples_per_frame * sizeof(int16_t));
            
            // 编码帧
            encode(codec_ctx, av_frame, new_av_pkt, out_file);
            
            // 移动剩余数据
            buffer_count -= samples_per_frame;
            if (buffer_count > 0) {
                memmove(sample_buffer, sample_buffer + samples_per_frame, 
                        buffer_count * sizeof(int16_t));
            }
        }
        
        count++;
    }

    // 刷新重采样器
    while (1) {
        int out_samples = swr_convert(swr_ctx, dst_data, frame_size * 4, NULL, 0);
        if (out_samples <= 0) break;
        
        int16_t *dst_samples = (int16_t *)dst_data[0];
        int samples_to_copy = out_samples * 2;
        
        // 扩展缓冲区
        if (buffer_count + samples_to_copy > buffer_size) {
            buffer_size = (buffer_count + samples_to_copy + samples_per_frame) * 2;
            int16_t *new_buf = av_realloc(sample_buffer, buffer_size * sizeof(int16_t));
            if (!new_buf) {
                fprintf(stderr, "Failed to reallocate sample buffer\n");
                break;
            }
            sample_buffer = new_buf;
        }
        
        memcpy(sample_buffer + buffer_count, dst_samples, samples_to_copy * sizeof(int16_t));
        buffer_count += samples_to_copy;
    }

    // 处理剩余样本（最后一帧）
    if (buffer_count > 0) {
        AVFrame *last_frame = av_frame_alloc();
        last_frame->nb_samples = buffer_count / 2;
        last_frame->format = AV_SAMPLE_FMT_S16;
        av_channel_layout_copy(&last_frame->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
        ret = av_frame_get_buffer(last_frame, 0);
        if (ret < 0) {
            fprintf(stderr, "Failed to allocate last frame buffers\n");
        } else {
            memcpy(last_frame->data[0], sample_buffer, buffer_count * sizeof(int16_t));
            encode(codec_ctx, last_frame, new_av_pkt, out_file);
        }
        av_frame_free(&last_frame);
    }
    
    // 刷新编码器
    encode(codec_ctx, NULL, new_av_pkt, out_file);
    
    printf("Recording completed. Processed %d packets\n", count);

    // 释放所有资源
    free_mem(codec_ctx, src_data, dst_data, swr_ctx, pkt, 
             fmt_ctx, av_frame, new_av_pkt, out_file, sample_buffer);
}